#if defined(_MSC_VER)
#pragma once
#endif

#ifndef LM_SHAPE_TRIANGLE_H
#define LM_SHAPE_TRIANGLE_H

#include "../core/lm.h"
#include "../core/shape.h"
#include "../core/texture.h"

class TriangleMesh : public Shape {
public:
	TriangleMesh(const Transform *o2w, const Transform *w2o, bool ro, Reference<Material> mat,
				int nt, int nv, const int *vi, const Point3 *P, const Normal *N, const Vector3 *S,
				const Point2 *uv, const Reference<Texture<float> > &atex);
	// Another constructor, load geometry mesh from wavefront obj file,
	// we only used vertex, face, normal, texture coordinate information, ignore others.
	TriangleMesh(const Transform *o2w, const Transform *w2o, bool ro, Reference<Material> mat, const string fileName, bool scale, const Reference<Texture<float>> &atex);
	~TriangleMesh();
	bool CanIntersect() const {
		return false;
	}
	BBox ObjectBound() const;
	BBox WorldBound() const;
	void Refine(vector<Reference<Shape>> &refined) const;
	friend class Triangle;
protected:
	// Number of triangles and vertex
	int ntris, nverts;
	// faces index
	// [t1_v0, t1_v1, t1_v2, t2_v0, t2_v1, t2_v3,...,]
	int *vindex;
	////////////////////////////////////////////////////////////////////////////
	// Note that p stored in world space while n, s, uvs stored in object space
	////////////////////////////////////////////////////////////////////////////
	
	// Real data
	// vertex
	Point3 *p;
	// normals
	Normal *n;
	// tangent vectors
	Vector3 *s;
	// texture coordinate
	Point2 *uvs;
	// alpha texture, used for leaves..
	Reference<Texture<float>> alphaTexture;
};

class Triangle : public Shape {
public:
	Triangle(const Transform *o2w, const Transform *w2o, bool ro, Reference<Material> mat, TriangleMesh *m, int n);
	~Triangle();
	BBox ObjectBound() const;
	BBox WorldBound() const;
	bool Intersect(const Ray &ray, Intersection *isect) const;
	bool IntersectP(const Ray &ray) const;
	void FillIntersection(const Ray &ray, Intersection *isect) const;
	void GetUVs(Point2 uv[3]) const;
	void GetShadingGeometry(const Intersection &isect) const;
	float Area() const;
	Point3 Sample(const Point2 &sample, Normal *Ns) const;
	void RenderGL(bool textured = false) const;
private:
	Reference<TriangleMesh> mesh;
	int *v;
};

#endif	// LM_SHAPE_TRIANGLE_H